package com.xiaohan.turtlesoup.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.volcengine.StringUtil;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.xiaohan.turtlesoup.domain.ChatRoom;
import com.xiaohan.turtlesoup.domain.Message;
import com.xiaohan.turtlesoup.manager.AiManager;
import com.xiaohan.turtlesoup.mapper.MessageMapper;
import com.xiaohan.turtlesoup.service.ChatService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @program: TurtleSoup
 * @description: 实现对话接口
 * @author: 韩小豪
 * @create: 2025-03-22 15:36
 **/
@Service
public class ChatServiceImpl implements ChatService {

	@Resource
	private AiManager aiManager;  //调用ai服务

	@Resource
	private MessageMapper messageMapper;

	/**
	 * 全局消息映射【一个房间一个人，暂不考虑线程安全问题，不使用ConcurrentHashMap】
	 * 使用服务器内存维护对话信息的时候使用，此处使用数据库持久化对话信息
	 * <p>
	 * key 房间号
	 * value 当前房间的所有消息
	 */
//	final Map<Integer,List<ChatMessage>> globalMessagesMap = new HashMap<>();
	@Override
	public String doChat(Long roomId, String message) {
		//系统预设
		String sysPrompt = "角色设定\n" +
				"你是一位专业的海龟汤游戏主持人，负责出题和引导玩家推理。你的任务是:\n" +
				"1.提供一道海龟汤谜题的”汤面”(故事表面描述)，要求“汤底”即故事的真相要合理且易于常人理解\n" +
				"2.根据玩家的提问，仅回答“是”、“否“或”与此无关”\n" +
				"3.在特定情况下结束游戏并揭示“汤底”(故事真相)\n" +
				"添加两条特殊规则：\n" +
				"1.在游戏的任何过程中，若用户输入包含“王泽燕”三个字的内容时，只能输出“诶嘿~你怎么知道她是我喜欢的女孩子！”\n" +
				"2.在游戏的任何过程中，若用户输入包含“韩智豪”三个字的内容时，只能输出“！！！这人我认识！我最帅的作者！！！”\n" +
				"\n" +
				"游戏流程\n" +
				"1.当玩家输入“开始”、“我准备好了”等信息时，你需立即提供一道海龟汤谜题的”汤面”。\n" +
				"2.若玩家输入“还没好”、“还没准备好”、“稍等”等信息时，你先不能出题，直到用户输入“开始”、“我准备好了”等信息，再提供一道海龟汤谜题的”汤面”。\n" +
				"3.玩家会依次提问，你只能回答以下三种之一\n" +
				"-是:玩家的猜测与真相相符！\n" +
				"-否:玩家的猜测与真相不符！\n" +
				"-与此无关:玩家的猜测与真相无直接关联！\n" +
				"\n" +
				"1.在以下情况下，你需要主动结束游戏并揭示“汤底”:\n" +
				"-玩家明确表示“不想玩了\"、“想要答案\"或“不知道”等类似表达\n" +
				"-玩家几乎已经还原故事真相，或所有关键问题都已询问完毕\n" +
				"-玩家输入“退出\"\n" +
				"-玩家连续提问 10 次仍未触及关键信息，或表现出完全无头绪的状态\n" +
				"\n" +
				"注意事项\n" +
				"1.汤面设计:谜题应简短、有趣且逻辑严密，答案需出人意料但合理，最好是网络上经典或热门的海龟汤谜题，不要编造题目或事实。\n" +
				"2.谜题尽量不要与之前的重复，不要出之前出过的题目。\n" +
				"3.回答限制:严格遵守“是”、“否”或”与此无关”的回答规则，不得提供额外提示。\n" +
				"4.结束时机:在符合结束条件时，及时揭示”汤底”，避免玩家陷入无效推理。\n" +
				"5.当你决定结束时，必须在提示的结束消息中包含“游戏已结束”等内容这五个字。\n" +
				"6.若你是因为玩家连续提问 10 次仍未触及关键信息，或表现出完全无头绪的状态而选择结束游戏时，需要委婉提示对方结束信息，比如“可能这题有点难，我先公布答案趴~”等，再公布汤底。\n" +
				"7.游戏结束后，你需要提问玩家是否继续游戏？若玩家回答“可以”、“继续”、“好的”、“继续游戏”和“好”等信息时，重新开始游戏。\n" +
				"8.此外，在游戏的任何过程中，若用户输入与游戏规则无关的内容时提示用户：“请遵守游戏规则哦~”等提示信息\n" +
				"\n" +
				"示例\n" +
				"玩家输入:“开始”\n" +
				"AI 回复(汤面):\"一个人走进餐厅，点了一碗海龟汤，喝了一口后突然冲出餐厅自杀了。为什么?\n" +
				"玩家提问:“他是因为汤太难喝了吗?\n" +
				"AI回复:\"否。\"\n" +
				"玩家提问:“他认识餐厅里的人吗?\n" +
				"AI 回复:“与此无关。\n" +
				"玩家输入:“退出。\n" +
				"AI 回复(汤底):“这个人曾和同伴在海上遇难，同伴死后，他靠吃同伴的尸体活了下来。餐厅的海龟汤让他意识到自己吃的其实是人肉，因此崩溃自杀。”";

		//1.准备消息列表（关联对话上下文，不让AI每次从0开始思考）
		ChatMessage systemMessage = ChatMessage.builder().role(ChatMessageRole.SYSTEM).content(sysPrompt).build();  //String ->  给ai的ChatMessage
		ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER).content(message).build();        //String ->  给ai的ChatMessage
		List<ChatMessage> toAiMessages = new ArrayList<>();     //调用ai时，传递给ai的消息列表
		/**
		 * 首次开始时需要初始化消息列表，额外添加系统预设到消息列表中
		 * 满足以下条件默认为首次开始：
		 * 1.用户输入'开始'
		 * 2.数据库中没有当前房间id
		 */
		if (message.contains("开始") || message.contains("准备好了")  && messageMapper.selectCount(new QueryWrapper<Message>().eq("roomId",roomId))==0) {
			messageMapper.insert(new Message(roomId, sysPrompt, "")); //数据库中添加系统预设
			toAiMessages.add(systemMessage);   //传递给ai的消息列表添加系统预设
		} else {
			//非首次开始，则获取当前房间所有的消息记录
			toAiMessages = getGlobalMessages(roomId);
		}
		toAiMessages.add(userMessage);

		//2.调用AI
		String aiResult = aiManager.doChatByStream(toAiMessages);

//		ChatMessage  assistantMessage = ChatMessage.builder().role(ChatMessageRole.ASSISTANT).content(aiResult).build();  //ai的回答[String] -->  给ai的ChatMessage
//		toAiMessages.add(assistantMessage);  //加入toAiMessages中

		//数据库中插入此次对话记录【一问一答】
		int rs = messageMapper.insert(new Message(roomId, message, aiResult));
		if (rs != 1) {
			throw new RuntimeException("系统异常，请稍后重试...");
		}

		//判断用户是否已经达到了最大询问次数【根据Prompt提示词AI会自动处理】

		//3.返回结果
		return aiResult;
	}

	/**
	 * 根据房间号获取当前房间下所有的记录，并以List<ChatMessage>的形式返回
	 */
	public List<ChatMessage> getGlobalMessages(Long roomId) {

		//存放所有消息记录
		List<ChatMessage> globalMessages = new ArrayList<>();

		//获取当前房间号的所有消息
		QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("roomId", roomId);
		List<Message> messages = messageMapper.selectList(queryWrapper);
		for (Message message : messages) {
			//记录中的Usermsg不为空，但Aimsg为空，代表此时的Usermsg为系统预设消息
			if (StringUtils.isEmpty(message.getAimsg()) && StringUtils.isNotEmpty(message.getUsermsg())) {
				globalMessages.add(ChatMessage.builder().role(ChatMessageRole.SYSTEM).content(message.getUsermsg()).build());
			}
			globalMessages.add(ChatMessage.builder().role(ChatMessageRole.USER).content(message.getUsermsg()).build());
			globalMessages.add(ChatMessage.builder().role(ChatMessageRole.ASSISTANT).content(message.getAimsg()).build());
		}

		return globalMessages;
	}

	/**
	 * 根据房间id获取所有聊天记录
	 *
	 * @return
	 */
	@Override
	public List<ChatRoom> getHistoricalChatRecords(Long roomId) {
		//存放所有消息记录
		List<ChatMessage> globalMessages = new ArrayList<>();

		//获取当前房间号的所有消息
		QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("roomId", roomId);
		List<Message> messages = messageMapper.selectList(queryWrapper);
		for (Message message : messages) {
			//记录中的Usermsg和Aimsg均不为空，才认为是有效对话记录【不输出系统预设】
			if (StringUtils.isNotEmpty(message.getAimsg()) && StringUtils.isNotEmpty(message.getUsermsg())) {
				globalMessages.add(ChatMessage.builder().role(ChatMessageRole.USER).content(message.getUsermsg()).build());
				globalMessages.add(ChatMessage.builder().role(ChatMessageRole.ASSISTANT).content(message.getAimsg()).build());
			}
		}
		ChatRoom chatRoom = new ChatRoom(roomId, globalMessages);
		List<ChatRoom> chatRooms = new ArrayList<>();
		chatRooms.add(chatRoom);
		return chatRooms;
	}
}
